/**
 * Copyright © 2016-2025 The Thingsboard Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.terracloud.server.controller;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import com.terracloud.server.common.data.log.PlatformLog;
import com.terracloud.server.common.data.log.PlatformStatistics;
import com.terracloud.server.common.data.id.UserId;
import com.terracloud.server.common.data.id.PlatformLogId;
import com.terracloud.server.common.data.log.LogLevel;
import com.terracloud.server.common.data.log.LogType;
import com.terracloud.server.common.data.page.PageData;
import com.terracloud.server.common.data.page.TimePageLink;
import com.terracloud.server.config.annotations.ApiOperation;
import com.terracloud.server.queue.util.TbCoreComponent;
import com.terracloud.server.service.log.PlatformLogService;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;

import static com.terracloud.server.controller.ControllerConstants.*;

@RestController
@TbCoreComponent
@RequestMapping("/api")
@RequiredArgsConstructor
@Slf4j
public class PlatformLogController extends BaseController {

    private final PlatformLogService platformLogService;

    @ApiOperation(value = "保存平台日志 (Save Platform Log)",
            notes = "创建或更新平台日志。" + TENANT_AUTHORITY_PARAGRAPH)
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "平台日志已成功保存",
                    content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                            schema = @Schema(implementation = PlatformLog.class))),
            @ApiResponse(responseCode = "400", description = "请求参数无效"),
            @ApiResponse(responseCode = "401", description = "用户未通过认证"),
            @ApiResponse(responseCode = "403", description = "用户无权限执行该操作"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")})
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/platform/log", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public DeferredResult<ResponseEntity<?>> savePlatformLog(@RequestBody PlatformLog platformLog) throws Exception {
        ListenableFuture<PlatformLog> future = toListenableFuture(() -> platformLogService.savePlatformLog(platformLog));
        return handlePlatformLogFuture(future);
    }

    @ApiOperation(value = "获取平台日志 (Get Platform Log)",
            notes = "根据日志ID获取平台日志。" + TENANT_AUTHORITY_PARAGRAPH)
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "平台日志",
                    content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                            schema = @Schema(implementation = PlatformLog.class))),
            @ApiResponse(responseCode = "400", description = "请求参数无效"),
            @ApiResponse(responseCode = "401", description = "用户未通过认证"),
            @ApiResponse(responseCode = "403", description = "用户无权限执行该操作"),
            @ApiResponse(responseCode = "404", description = "平台日志未找到"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")})
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/platform/log/{logId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public DeferredResult<ResponseEntity<?>> getPlatformLogById(@PathVariable("logId") String strLogId) throws Exception {
        checkParameter("logId", strLogId);
        PlatformLogId logId = new PlatformLogId(toUUID(strLogId));
        ListenableFuture<PlatformLog> future = toListenableFuture(() -> platformLogService.findPlatformLogById(logId));
        return handlePlatformLogFuture(future);
    }

    @ApiOperation(value = "删除平台日志 (Delete Platform Log)",
            notes = "根据日志ID删除平台日志。" + TENANT_AUTHORITY_PARAGRAPH)
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "平台日志已成功删除"),
            @ApiResponse(responseCode = "400", description = "请求参数无效"),
            @ApiResponse(responseCode = "401", description = "用户未通过认证"),
            @ApiResponse(responseCode = "403", description = "用户无权限执行该操作"),
            @ApiResponse(responseCode = "404", description = "平台日志未找到"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")})
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/platform/log/{logId}", method = RequestMethod.DELETE)
    @ResponseStatus(value = HttpStatus.OK)
    public DeferredResult<ResponseEntity<?>> deletePlatformLog(@PathVariable("logId") String strLogId) throws Exception {
        checkParameter("logId", strLogId);
        PlatformLogId logId = new PlatformLogId(toUUID(strLogId));
        ListenableFuture<Void> future = toListenableFuture(() -> {
            platformLogService.deletePlatformLog(logId);
            return null;
        });
        return handleVoidFuture(future);
    }

    @ApiOperation(value = "获取平台日志列表 (Get Platform Logs)",
            notes = "获取所有符合条件的平台日志列表。" + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "平台日志分页数据",
                    content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                            schema = @Schema(implementation = PageData.class))),
            @ApiResponse(responseCode = "400", description = "请求参数无效"),
            @ApiResponse(responseCode = "401", description = "用户未通过认证"),
            @ApiResponse(responseCode = "403", description = "用户无权限执行该操作"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")})
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/platform/logs", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public DeferredResult<ResponseEntity<?>> getPlatformLogs(
            @RequestParam int pageSize,
            @RequestParam int page,
            @RequestParam(required = false) String textSearch,
            @RequestParam(required = false) String sortProperty,
            @RequestParam(required = false) String sortOrder,
            @RequestParam(required = false) Long startTime,
            @RequestParam(required = false) Long endTime,
            @RequestParam(required = false) String logType,
            @RequestParam(required = false) String logLevel,
            @RequestParam(required = false) String userId) throws Exception {
        
        TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
        ListenableFuture<PageData<PlatformLog>> future;
        
        if (userId != null && !userId.isEmpty()) {
            UserId user = new UserId(toUUID(userId));
            if (logType != null && !logType.isEmpty()) {
                LogType type = LogType.valueOf(logType);
                future = toListenableFuture(() -> platformLogService.findPlatformLogsByTenantIdAndType(getCurrentUser().getTenantId(), type, pageLink));
            } else if (logLevel != null && !logLevel.isEmpty()) {
                LogLevel level = LogLevel.valueOf(logLevel);
                future = toListenableFuture(() -> platformLogService.findPlatformLogsByTenantIdAndLevel(getCurrentUser().getTenantId(), level, pageLink));
            } else {
                future = toListenableFuture(() -> platformLogService.findPlatformLogsByTenantIdAndUserId(getCurrentUser().getTenantId(), user, pageLink));
            }
        } else {
            if (logType != null && !logType.isEmpty()) {
                LogType type = LogType.valueOf(logType);
                future = toListenableFuture(() -> platformLogService.findPlatformLogsByTenantIdAndType(getCurrentUser().getTenantId(), type, pageLink));
            } else if (logLevel != null && !logLevel.isEmpty()) {
                LogLevel level = LogLevel.valueOf(logLevel);
                future = toListenableFuture(() -> platformLogService.findPlatformLogsByTenantIdAndLevel(getCurrentUser().getTenantId(), level, pageLink));
            } else {
                future = toListenableFuture(() -> platformLogService.findPlatformLogsByTenantId(getCurrentUser().getTenantId(), pageLink));
            }
        }
        
        return handlePageDataFuture(future);
    }

    @ApiOperation(value = "获取平台日志统计信息 (Get Platform Log Statistics)",
            notes = "获取平台日志的所有统计信息。" + TENANT_AUTHORITY_PARAGRAPH)
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "平台日志统计信息",
                    content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                            schema = @Schema(implementation = PlatformStatistics.class))),
            @ApiResponse(responseCode = "401", description = "用户未通过认证"),
            @ApiResponse(responseCode = "403", description = "用户无权限执行该操作"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")})
    @PreAuthorize("hasAuthority('TENANT_ADMIN')")
    @RequestMapping(value = "/platform/logs/statistics", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public DeferredResult<ResponseEntity<?>> getPlatformLogStatistics() throws Exception {
        ListenableFuture<PlatformStatistics> future = toListenableFuture(() -> platformLogService.getPlatformStatistics(getCurrentUser().getTenantId()));
        return handlePlatformStatisticsFuture(future);
    }

    private <T> ListenableFuture<T> toListenableFuture(SupplierWithException<T> supplier) {
        SettableFuture<T> future = SettableFuture.create();
        try {
            T result = supplier.get();
            future.set(result);
        } catch (Exception e) {
            future.setException(e);
        }
        return future;
    }

    private DeferredResult<ResponseEntity<?>> handlePlatformLogFuture(ListenableFuture<PlatformLog> future) {
        DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
        Futures.addCallback(future, new FutureCallback<>() {
            @Override
            public void onSuccess(PlatformLog result) {
                deferredResult.setResult(ResponseEntity.ok(result));
            }

            @Override
            public void onFailure(@NotNull Throwable t) {
                deferredResult.setErrorResult(t);
            }
        }, MoreExecutors.directExecutor());
        return deferredResult;
    }

    private DeferredResult<ResponseEntity<?>> handleVoidFuture(ListenableFuture<Void> future) {
        DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
        Futures.addCallback(future, new FutureCallback<Void>() {
            @Override
            public void onSuccess(Void result) {
                deferredResult.setResult(ResponseEntity.ok(HttpStatus.OK));
            }

            @Override
            public void onFailure(@NotNull Throwable t) {
                deferredResult.setErrorResult(t);
            }
        }, MoreExecutors.directExecutor());
        return deferredResult;
    }

    private DeferredResult<ResponseEntity<?>> handlePageDataFuture(ListenableFuture<PageData<PlatformLog>> future) {
        DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
        Futures.addCallback(future, new FutureCallback<PageData<PlatformLog>>() {
            @Override
            public void onSuccess(PageData<PlatformLog> result) {
                deferredResult.setResult(ResponseEntity.ok(result));
            }

            @Override
            public void onFailure(@NotNull Throwable t) {
                deferredResult.setErrorResult(t);
            }
        }, MoreExecutors.directExecutor());
        return deferredResult;
    }

    private DeferredResult<ResponseEntity<?>> handleLongFuture(ListenableFuture<Long> future) {
        DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
        Futures.addCallback(future, new FutureCallback<Long>() {
            @Override
            public void onSuccess(Long result) {
                deferredResult.setResult(ResponseEntity.ok(result));
            }

            @Override
            public void onFailure(@NotNull Throwable t) {
                deferredResult.setErrorResult(t);
            }
        }, MoreExecutors.directExecutor());
        return deferredResult;
    }

    private DeferredResult<ResponseEntity<?>> handleDoubleFuture(ListenableFuture<Double> future) {
        DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
        Futures.addCallback(future, new FutureCallback<Double>() {
            @Override
            public void onSuccess(Double result) {
                deferredResult.setResult(ResponseEntity.ok(result));
            }

            @Override
            public void onFailure(@NotNull Throwable t) {
                deferredResult.setErrorResult(t);
            }
        }, MoreExecutors.directExecutor());
        return deferredResult;
    }

    private DeferredResult<ResponseEntity<?>> handlePlatformStatisticsFuture(ListenableFuture<PlatformStatistics> future) {
        DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
        Futures.addCallback(future, new FutureCallback<PlatformStatistics>() {
            @Override
            public void onSuccess(PlatformStatistics result) {
                deferredResult.setResult(ResponseEntity.ok(result));
            }

            @Override
            public void onFailure(@NotNull Throwable t) {
                deferredResult.setErrorResult(t);
            }
        }, MoreExecutors.directExecutor());
        return deferredResult;
    }

    @FunctionalInterface
    private interface SupplierWithException<T> {
        T get() throws Exception;
    }
}